#include <iostream>
#include <pthread.h>
#include <string>
#include <vector>
#include <unistd.h>
#include <cstring>
#include <cstdio>
#include <memory>
#include "Thread.hpp"
#include "Mutex.hpp"

using std::cout;
using std::endl;

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
int train_tickets = 1000;
class ThreadData
{
public:
    ThreadData(std::string threadname, pthread_mutex_t *lock)
        : _threadname(threadname),
          _lock(lock)
    {
    }
    ~ThreadData()
    {
    }

public:
    std::string _threadname;
    pthread_mutex_t *_lock;
};
void *get_train_tickets(void *args)
{
    std::string user_name = static_cast<const char *>(args);
    while (1)
    {
        {//不想把usleep也加锁，加一个花括号，就相当于一个作用域了
            // 加锁
            LockGuard lockguard(&lock);//RAII操作
            if (train_tickets > 0)
            {
                usleep(1000);
                printf("%s正在进行抢票 : %d\n", user_name.c_str(), train_tickets);
                train_tickets--;
            }
            else
            {
                break;//这里break也不怕了，因为出了作用域，lockguard对象自动销毁，调用析构
            }
        }
        usleep(1000);
    }
}
int main()
{
    pthread_t t1, t2, t3, t4;
    pthread_create(&t1, nullptr, get_train_tickets, (void *)"thread 1");
    pthread_create(&t2, nullptr, get_train_tickets, (void *)"thread 2");
    pthread_create(&t3, nullptr, get_train_tickets, (void *)"thread 3");
    pthread_create(&t4, nullptr, get_train_tickets, (void *)"thread 4");
    pthread_join(t1, nullptr);
    pthread_join(t2, nullptr);
    pthread_join(t3, nullptr);
    pthread_join(t4, nullptr);

    return 0;
}

// int train_tickets = 1000;
// class ThreadData
// {
// public:
//     ThreadData(std::string threadname, pthread_mutex_t *lock)
//         : _threadname(threadname),
//           _lock(lock)
//     {
//     }
//     ~ThreadData()
//     {
//     }

// public:
//     std::string _threadname;
//     pthread_mutex_t *_lock;
// };
// static pthread_mutex_t lock;
// void *get_train_tickets(void *args)
// {
//     std::string user_name = static_cast<const char *>(args);
//     while (1)
//     {
//         pthread_mutex_lock(&lock);
//         pthread_mutex_lock(&lock);
//         if (train_tickets > 0)
//         {
//             usleep(1000);
//             printf("%s正在进行抢票 : %d\n", user_name.c_str(), train_tickets);
//             train_tickets--;
//             pthread_mutex_unlock(&lock);
//         }
//         else
//         {
//             pthread_mutex_unlock(&lock);//如果if为假，直接走else，那么锁没有被解锁，所以这里要解锁
//             break;
//         }
//         usleep(1000);
//     }
// }
// int main()
// {
//     pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
//     pthread_t t1, t2, t3, t4;
//     pthread_create(&t1, nullptr, get_train_tickets, (void *)"thread 1");
//     pthread_create(&t2, nullptr, get_train_tickets, (void *)"thread 2");
//     pthread_create(&t3, nullptr, get_train_tickets, (void *)"thread 3");
//     pthread_create(&t4, nullptr, get_train_tickets, (void *)"thread 4");
//     pthread_join(t1, nullptr);
//     pthread_join(t2, nullptr);
//     pthread_join(t3, nullptr);
//     pthread_join(t4, nullptr);

//     return 0;
// }

// int train_tickets = 1000;
// void *get_train_tickets(void *args)
// {
//     ThreadData *td = static_cast<ThreadData *>(args);
//     while (1)
//     {
//         pthread_mutex_lock(td->_lock);
//         if (train_tickets > 0)
//         {
//             usleep(1000);
//             printf("%s正在进行抢票 : %d\n", td->_threadname.c_str(), train_tickets);
//             train_tickets--;
//             pthread_mutex_unlock(td->_lock);
//         }
//         else
//         {
//             pthread_mutex_unlock(td->_lock);
//             break;
//         }
//         usleep(1000);
//     }
// }

// int main()
// {
// #define NUM 4
//     pthread_mutex_t lock;
//     pthread_mutex_init(&lock, nullptr);
//     std::vector<pthread_t> tids(NUM);
//     for (size_t i = 0; i < NUM; ++i)
//     {
//         char buffer[128];
//         snprintf(buffer, sizeof buffer, "thread %d", i + 1); // i+1使得新线程id不从0开始
//         ThreadData *td = new ThreadData(buffer, &lock);
//         pthread_create(&tids[i], nullptr, get_train_tickets, td);
//     }
//     for (const auto &tid : tids)
//     {
//         pthread_join(tid, nullptr);
//     }
//     pthread_mutex_destroy(&lock);
//     // pthread_t t1, t2, t3, t4;
//     //  pthread_create(&t1, nullptr, get_train_tickets, (void *)"thread 1");
//     //  pthread_create(&t2, nullptr, get_train_tickets, (void *)"thread 1");
//     //  pthread_create(&t3, nullptr, get_train_tickets, (void *)"thread 1");
//     //  pthread_create(&t4, nullptr, get_train_tickets, (void *)"thread 1");

//     // pthread_join(t1, nullptr);
//     // pthread_join(t2, nullptr);
//     // pthread_join(t3, nullptr);
//     // pthread_join(t4, nullptr);

//     // pthread_mutex_destroy(&lock);
//     return 0;
// }

// pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;//全局锁直接使用PTHREAD_MUTEX_INITIALIZER初始化就行

// int train_tickets = 1000;
// void *get_train_tickets(void *args)
// {
//     std::string user_name = static_cast<const char *>(args);
//     while (1)
//     {
//         pthread_mutex_lock(&mutex);
//         if (train_tickets > 0)
//         {
//             usleep(1000);
//             printf("%s正在进行抢票 : %d\n", user_name.c_str(), train_tickets);
//             train_tickets--;
//             pthread_mutex_unlock(&mutex);
//         }
//         else
//         {
//             pthread_mutex_unlock(&mutex);//如果if为假，直接走else，那么锁没有被解锁，所以这里要解锁
//             break;
//         }
//     }
// }
// int main()
// {
//     std::unique_ptr<Thread> thread1(new Thread(get_train_tickets, (void *)"user 1", 1));
//     std::unique_ptr<Thread> thread2(new Thread(get_train_tickets, (void *)"user 2", 2));
//     std::unique_ptr<Thread> thread3(new Thread(get_train_tickets, (void *)"user 3", 3));
//     thread1->join();
//     thread2->join();
//     thread3->join();
//     return 0;
// }
// // 这里我们要看到的现象是 ： —— 票有可能被抢为负数！
// // 我们需要让多个线程进行并行交叉执行，usleep休眠切换进程！
// // 多个线程并行交叉执行的本质：cpu内的调度器频繁的发生线程进行切换和调度
// // 线程一般什么时候发生切换呢？ —— 1、时间片到了；2、来了更高优先级的线程；3、线程等待的时候
// // 线程什么时候检测：时间片到了，来了优先级更高的线程，线程等待这些问题呢？
// // 线程从内核态返回用户态的时候，线程要对调度状态进行检测，如果可以就直接发生线程切换！
// int train_tickets = 1000; // 火车票
// void *get_train_tickets(void *args)
// {
//     std::string user_name = static_cast<const char *>(args);
//     while (1)
//     {
//         if (train_tickets > 0) // 有票才能抢
//         {
//             // 用这段时间来模拟抢票真实需要花费的时间
//             usleep(1000); // 1s = 1000毫秒 = 1000 000微秒 = 1000 000 000纳秒
//             printf("%s正在进行抢票 : %d\n", user_name.c_str(), train_tickets);
//             train_tickets--;
//         }
//         else
//             break;
//     }
// }
// int main()
// {
//     std::unique_ptr<Thread> thread1(new Thread(get_train_tickets, (void *)"user 1", 1));
//     std::unique_ptr<Thread> thread2(new Thread(get_train_tickets, (void *)"user 2", 2));
//     std::unique_ptr<Thread> thread3(new Thread(get_train_tickets, (void *)"user 3", 3));
//     thread1->join();
//     thread2->join();
//     thread3->join();
//     return 0;
// }

// void *thread_run(void *args) // 线程执行函数
// {
//     std::string work_type = static_cast<const char *>(args);
//     while (1)
//     {
//         printf("我是一个新线程,我正在做 : %s\n", work_type.c_str());
//         sleep(1);
//     }
// }
// int main()
// {
//     std::unique_ptr<Thread> thread1(new Thread(thread_run, (void *)"thread 1", 1));
//     std::unique_ptr<Thread> thread2(new Thread(thread_run, (void *)"thread 2", 2));
//     std::unique_ptr<Thread> thread3(new Thread(thread_run, (void *)"thread 3", 3));

//     // thread1->start();//如果把Thread.hpp的start放到构造函数外面，这里就要调start函数
//     // thread2->start();
//     // thread3->start();

//     thread1->join();
//     thread2->join();
//     thread3->join();

//     return 0;
// }

// __thread int g_val = 100;

// std::string ThreadId(const pthread_t &pthtred_id)
// {
//     char buffer[128];
//     snprintf(buffer, sizeof(buffer), "0x%x", pthread_self());
//     return buffer;
// }
// void *start_toutine(void *args)
// {
//     std::string name = static_cast<const char *>(args);
//     while (1)
//     {
//         printf(" new thread : g_val : %d &g_val : %p\n", g_val, &g_val);
//         sleep(1);
//         g_val++;
//     }
//     return nullptr;
// }
// int main()
// {
//     pthread_t tid;
//     pthread_create(&tid, nullptr, start_toutine, (void *)"thread 1");
//     std::string main_tid = ThreadId(pthread_self());
//     pthread_detach(tid);
//     while (1)
//     {
//         printf("main thread : g_val : %d &g_val : %p\n", g_val, &g_val);
//         sleep(1);
//     }
//     return 0;
// }

// #include <iostream>
// #include <pthread.h>
// #include <string>
// #include <unistd.h>
// #include <cstring>
// #include <cstdio>
// using std::cout;
// using std::endl;
// std::string ThreadId(const pthread_t &pthtred_id)
// {
//     char buffer[128];
//     snprintf(buffer, sizeof(buffer), "0x%x", pthread_self());
//     return buffer;
// }
// void *start_toutine(void *args)
// {
//     std::string name = static_cast<const char *>(args);
//     int cnt = 5;
//     while (cnt--)
//     {
//         printf("%s running... %s\n", name.c_str(), ThreadId(pthread_self()).c_str());
//         sleep(1);
//     }
//     return nullptr;
// }
// int main()
// {
//     pthread_t tid;
//     pthread_create(&tid, nullptr, start_toutine, (void *)"thread 1");
//     std::string main_tid = ThreadId(pthread_self());
//     pthread_detach(tid);
//     printf("main thread running... new thread id : %s —— main threead id : %s\n", ThreadId(tid).c_str(), main_tid.c_str());
//     while (1)
//     {
//         //主线程做自己的事情...
//         printf("result : %d : %s\n", n, strerror(n));
//     }
//     return 0;
// }

// std::string ThreadId(const pthread_t &pthtred_id)
// {
//     char buffer[128];
//     snprintf(buffer, sizeof(buffer), "0x%x", pthread_self());
//     return buffer;
// }
// void *start_toutine(void *args)
// {
//     std::string name = static_cast<const char *>(args);
//     //pthread_detach(pthread_self()); // 线程将自己分离！
//     int cnt = 5;
//     while (cnt--)//先不分离线程，先检查5s之后线程等待的值是不是0
//     {
//         printf("%s running... %s\n", name.c_str(), ThreadId(pthread_self()).c_str());
//         sleep(1);
//     }
//     return nullptr;
// }
// int main()
// {
//     pthread_t tid;
//     pthread_create(&tid, nullptr, start_toutine, (void *)"thread 1");
//     std::string main_tid = ThreadId(pthread_self());
//     pthread_detach(tid);
//     printf("main thread running... new thread id : %s —— main threead id : %s\n", ThreadId(tid).c_str(), main_tid.c_str());
//     // 一个线程创建出来默认是joinable的，如果设置了分离状态，就不能再对该线程进行等待了
//     //sleep(2);
//     int n = pthread_join(tid, nullptr);
//     printf("result : %d : %s\n", n, strerror(n));//5s之后n应该是0
//     return 0;
// }

// std::string ThreadId(const pthread_t &pthtred_id)
// {
//     char buffer[128];
//     snprintf(buffer, sizeof(buffer), "0x%x", pthread_self());
//     return buffer;
// }
// void *start_toutine(void *args)
// {
//     std::string name = static_cast<const char *>(args);
//     while (1)
//     {
//         // 这里pthread_self获取到的id必须和下面主函数ThreadId获取到的id是一样的！
//         printf("%s running... %s\n", name.c_str(), ThreadId(pthread_self()).c_str());
//         sleep(1);
//     }
// }
// int main()
// {
//     pthread_t tid;
//     pthread_create(&tid, nullptr, start_toutine, (void *)"thread 1");
//     std::string main_tid = ThreadId(pthread_self()); // 获取主线程id
//     printf("main thread running... new thread id : %s —— main threead id : %s\n", ThreadId(tid).c_str(), main_tid.c_str());
//     pthread_join(tid, nullptr);
//     return 0;
// }

// void *start_toutine(void *args)
// {
//     std::string name = static_cast<const char *>(args);
//     while (1)
//     {
//         //这里和上面不同，采用printf向一个流(stdout)打印结果是原子性的！
//         printf("%s\n", name.c_str());//字符串要记得转换称为c类型的，头文件cstring
//         sleep(1);
//     }
// }
// int main()
// {
//     pthread_t tid;
//     pthread_create(&tid, nullptr, start_toutine, (void *)"thread 1");
//     pthread_join(tid, nullptr);
//     return 0;
// }